package yc.star.forum.config;


import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.loader.ClassPathDocumentLoader;
import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import yc.star.forum.repository.RedisChatMemoryStore;


import java.util.List;

/**
 * AI聊天系统通用配置类
 * 配置langchain4j框架相关的Bean，包括聊天记忆、向量数据库、RAG检索等功能
 * 为论坛的AI助手提供完整的技术支持
 */
@Configuration
public class CommonConfig {

    /**
     * Redis聊天记忆存储，用于持久化聊天历史
     */
    @Autowired
    private RedisChatMemoryStore redisChatMemoryStore;
    
    /**
     * 向量化模型，用于将文本转换为向量表示
     */
    @Autowired
    private EmbeddingModel embeddingModel;
    
    /**
     * Redis向量存储，用于存储和检索文档向量
     */
    @Autowired
    private RedisEmbeddingStore redisEmbeddingStore;

    /**
     * 自定义OpenAI流式聊天模型配置
     * 明确指定UTF-8编码处理，确保中文字符正确显示
     */
    @Bean
    public OpenAiStreamingChatModel openAiStreamingChatModel() {
        return OpenAiStreamingChatModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey("sk-16119d347103437da6c0105b1efad1fa")
                .modelName("qwen-plus")
                .temperature(0.7)
                .maxTokens(2000)
                .logRequests(true)
                .logResponses(true)
                .build();
    }
    
    /**
     * 自定义OpenAI聊天模型配置
     * 明确指定UTF-8编码处理，确保中文字符正确显示
     */
    @Bean
    public OpenAiChatModel openAiChatModel() {
        return OpenAiChatModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey("sk-16119d347103437da6c0105b1efad1fa")
                .modelName("qwen-plus")
                .logRequests(true)
                .logResponses(true)
                .build();
    }
    
    // 向量模型配置暂时注释，使用默认配置
    // OpenAiEmbeddingModel类可能在当前版本中不可用
    /*
    @Bean
    public OpenAiEmbeddingModel openAiEmbeddingModel() {
        return OpenAiEmbeddingModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey("sk-16119d347103437da6c0105b1efad1fa")
                .modelName("text-embedding-v3")
                .logRequests(true)
                .logResponses(true)
                .build();
    }
    */

    /**
     * 配置聊天上下文记忆Bean
     * 使用滑动窗口模式，最多保留20条消息
     * @return ChatMemory 聊天记忆对象
     */
    @Bean
    public ChatMemory chatMemory () {
        // 构建消息窗口聊天记忆，限制最大消息数为20
        MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(20).build();
        return chatMemory;
    }

    /**
     * 配置聊天记忆提供者Bean
     * 为每个会话提供独立的聊天记忆，支持多用户并发聊天
     * @return ChatMemoryProvider 聊天记忆提供者
     */
    @Bean
    public ChatMemoryProvider chatMemoryProvider () {
        ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider() {

            /**
             * 根据会话ID获取对应的聊天记忆
             * @param memoryId 会话ID，用于区分不同用户的聊天会话
             * @return ChatMemory 该会话的聊天记忆对象
             */
            @Override
            public ChatMemory get(Object memoryId) {
                return MessageWindowChatMemory.builder()
                        .id(memoryId) // 设置会话ID
                        .chatMemoryStore(redisChatMemoryStore) // 使用Redis存储
                        .maxMessages(20) // 最多保留20条消息
                        .build();
            }
        };
        return chatMemoryProvider;
    }

    /**
     * 构建向量数据库操作对象(RAG - 检索增强生成)
     * 加载文档并将其向量化存储到Redis中，为AI提供知识库支持
     * @return EmbeddingStore 向量存储对象
     */
    @Bean
    public EmbeddingStore store () {
        // 从classpath的content目录加载文档，支持PDF文件解析
//        List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
        // 使用Apache PDFBox解析器加载PDF文档
        List<Document> documents = ClassPathDocumentLoader.loadDocuments("content",new ApachePdfBoxDocumentParser());
        
        // 备用：内存版本的向量存储器
//        InMemoryEmbeddingStore embeddingStore = new InMemoryEmbeddingStore();
        
        // 配置文档分割器：每个片段最大500字符，重叠100字符
        DocumentSplitter ds = DocumentSplitters.recursive(500,100);
        
        // 构建向量存储摄取器
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor
                .builder()
                .embeddingStore(redisEmbeddingStore) // 使用Redis向量存储
                .documentSplitter(ds) // 设置文档分割器
                .embeddingModel(embeddingModel)  // 设置向量化模型
                .build();
        
        // 将文档摄取到向量数据库中
        ingestor.ingest(documents);
        return redisEmbeddingStore;
    }

    /**
     * 构建向量数据库检索对象(RAG)
     * 用于从向量数据库中检索与用户问题相关的文档内容
     * @return ContentRetriever 内容检索器
     */
    @Bean
    public ContentRetriever contentRetriever (/*EmbeddingStore store*/) {
        return EmbeddingStoreContentRetriever
                .builder()
                .embeddingStore(redisEmbeddingStore) // 使用Redis向量存储
                .minScore(0.6) // 设置最小相似度阈值为0.6
                .maxResults(3) // 最多返回3个相关结果
                .embeddingModel(embeddingModel)  // 使用向量化模型进行查询向量化
                .build();
    }
}
